(function(global,factory){
    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
    typeof define === 'function' && define.amd ? define(factory) :
    (global = global || self, global.xhr = factory());
}(this,function(){

    let dftXHR = {
        url: null// 请求地址
        ,method: 'POST'// 请求类型
        ,data: {}// 传递数据
        ,async: true// 是否异步执行
        ,dataType:''//''默认值text
        ,contentType:''//可以指定application/json
        ,header:{
            // 设置请求主体的数据类型
            'Content-Type':'application/x-www-form-urlencoded; charset=utf-8'
        }
        ,progress:function(){}
        ,before: function(){}// 请求发送前执行事件
        ,complete: function(){}// 请求发送后执行事件
        ,success: function(){}// 请求成功后执行事件
        ,fail: function(){}// 请求失败后执行事件
    }

    ,REGJSON = /application\/json/

    ,isEmptyObj = function(obj){
        return JSON.stringify(obj) == '{}'
    }
    
    ,isObj = function(obj){
        return typeof obj == 'object' && obj != null;
    }
    , sendxhr = function(options){
        return new Promise(function(resolve,reject){
            let setting = Object.assign({},dftXHR,options)
            ,header = setting.header
            ,xhr = new XMLHttpRequest()
            ,method = setting.method.toUpperCase()
            // ,getQueryStr = method == 'GET' && /[^?]+(\?[\s\S]+)?/.exec(setting.url)[1] || ''
            ,setParams = function(){
                xhr.timeout = 25000;
                //设置想要的数据类型
                xhr.responseType = setting.dataType;
                xhr.open(method,setting.url,setting.async);
                // 此方法需要在open方法和send方法之间调用
                REGJSON.test(setting.contentType) && (header['Content-Type'] = setting.contentType)
                for(let key in header){
                    xhr.setRequestHeader(key,header[key]);
                }
            }()
                  
            ,evtListener = function(){
                xhr.addEventListener('loadstart', function(){ 
                    setting.before(this);
                });
                //上传进度
                xhr.addEventListener('progress',function(e){
                    //长度可计算并且readyState == '3'
                    if(e.lengthComputable){
                        setting.progress.call(this,e,e.loaded,e.total)
                    }
                })
    
                // 监听onreadystatechange并执行成功失败事件
                // readyState可以用onload代替
                // xhr.addEventListener('readystatechange',function(){
                //    if(xhr.readyState === 4 && (xhr.status >= 200 && xhr.status < 300 || xhr.status==304)){
                //        setting.success.call(xhr,xhr.response,xhr.status)
                //    }
                // })
    
                //请求成功的事件
                xhr.onload = function(){
                    setting.success.call(this,this.response,this.status);
                    resolve.call(this,this.response,this.status);
                };
    
                //请求失败回调
                xhr.addEventListener('error',function(){ 
                    setting.fail.call(this,this.status,this.statusText);
                    reject.call(this,this.status,this.statusText);
                })
                xhr.addEventListener('timeout',function(){
                    setting.fail.call(this,this.status,this.statusText);
                    reject.call(this,this.status,this.statusText);
                    this.abort();
                })
    
                //无论请求成功还是失败都会执行的事件，
                xhr.addEventListener('loadend',function(){
                    setting.complete.call(this,this.status,this.statusText);
                })
            }()
            //请求主体数据
            ,bodyData = function(data){ 
                if(setting.contentType && REGJSON.test(setting.contentType)){
                    return JSON.stringify(data);
                }else{
                    let formData = new FormData()
                    //对象扁平化处理
                    , flatObj = function(data,name){
                        Object.keys(data).forEach(function(key,i){
                            //将key值注入到formData对象中
                            let value = data[key];
                            if(isObj(value)){
                                key = !name && key || name+'['+key+']'
                                flatObj(value,key);
                            }else{
                                key = !name && key || name+'['+key+']'
                                formData.append(key,value);
                            }
                        })
                    };
                    flatObj(data)
                    return formData;
                }
            }
            xhr.send(method == 'POST' && !isEmptyObj(setting.data) && bodyData(setting.data)||null);
        })
    }
    return sendxhr;
}))